﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SilverTile.Xaml;
using SilverTile.Sprites;
using System.Linq;
using System.Collections.Generic;
using SilverTile.ExtensionMethods;
using System.IO;
using System.Windows.Markup;
using SilverTile;
using System.ComponentModel;

namespace SilverTileApp
{
    public class GameImplementation : SilverTileGame, INotifyPropertyChanged
    {

        public const int ViewportWidth = 512;
        public const int ViewportHeight = 288;
        public static readonly TimeSpan AddNewMonsterInterval = TimeSpan.FromSeconds(1.0);
        public const int AddNewMonsterProbability = 10;

        private ResourceDictionary _resources;

        private List<ISprite> _monstersHit = new List<ISprite>();

        private TimeSpan _addNewMonsterTime;

        public GameImplementation()
            : base()
        {
            Width = ViewportWidth;
            Height = ViewportHeight;

            _addNewMonsterTime = TimeSpan.Zero;

            Loaded += (s,e) => LoadGame("/SilverTileApp;component/GameData.xaml", "World");

        }

        private void LoadGame(string resourceUri, string worldResourceKey)
        {

            _resources = DowloadResourceDictionary(resourceUri);
            GameWorld = (SilverTileGameWorld)_resources[worldResourceKey];

            GameWorld.AreaTransitionAction = PerformAreaTransition;
            GameWorld.Spawned += GameWorld_Spawned;

            var player = _resources.GetSprite<PlayerSprite>("Player");
            player.Viewport = Viewport;
            player.X = 10;
            player.Y = 125;
            player.SetDirection(Direction.Left);
            GameWorld.PlayerSprite = player;

            SwordSprite sword = _resources.GetSprite<SwordSprite>("Sword");
            sword.Player = player;
            sword.SwordHitWall = SwordHit;
            sword.SwordHitMonster = SwordHitMonster;
            sword.IsVisible = false;
            Viewport.AddSprite("Sword", sword);
            player.Sword = sword;

            // Add a monster
            //AddNewMonster(256,1);

        }

        private void GameWorld_Spawned(object sender, SilverTileGameWorld.SpawnedEventArgs e)
        {

            
            int x = ActiveGameArea.TileWidth * e.Tile.X;
            int y = ActiveGameArea.TileHeight * e.Tile.Y;
            AddNewMonster(x, y);

        }

        private ResourceDictionary DowloadResourceDictionary(string uri)
        {
            using (Stream levelStream = Application.GetResourceStream(new Uri(uri, UriKind.Relative)).Stream)
            using (StreamReader levelReader = new StreamReader(levelStream))
            {
                return (ResourceDictionary)XamlReader.Load(levelReader.ReadToEnd());
            }
        }


        public override void Update(TimeSpan timeSinceLastFrame)
        {

            ISprite player = GameWorld.PlayerSprite;

            var collisions = Viewport.GetForegroundSpriteCollisions(player, -1).Where(s => s is MonsterSprite).ToList();
            if (collisions.Count() > 0)
            {
                PlayerDied();
            }

            foreach (ISprite monster in _monstersHit)
            {
                Viewport.RemoveSprite(monster);
                NumKilled++;
                if (Rnd.Next(4) > 0)
                {
                    //AddNewMonster();
                }
            }
            _monstersHit.Clear();

            AddRandomNewMonster(timeSinceLastFrame);
            
            base.Update(timeSinceLastFrame);
        }

        private void AddRandomNewMonster(TimeSpan timeSinceLastFrame)
        {
            _addNewMonsterTime += timeSinceLastFrame;

            if (_addNewMonsterTime > AddNewMonsterInterval)
            {
                _addNewMonsterTime -= AddNewMonsterInterval;
                if (Rnd.Next(100) <= AddNewMonsterProbability)
                {
                    //AddNewMonster();
                }
            }

        }

        private int _numKilled = 0;
        public int NumKilled { 
            get { return _numKilled; }
            private set
            {
                _numKilled = value;
                RaisePropertyChanged("NumKilled");
            }
        }

        private bool _isAlive = true;
        public bool IsAlive
        {
            get { return _isAlive; }
            private set
            {
                _isAlive = value;
                RaisePropertyChanged("IsAlive");
            }
        }

        private void PlayerDied()
        {
            IsAlive = false;
            Running = false;
        }

        private void MonsterKilled(ISprite monsterSprite)
        {
            _monstersHit.Add(monsterSprite);
        }

        public void AddNewMonster(int x, int y)
        {

            var monsterSprite = _resources.GetSprite<MonsterSprite>("Monster");
            monsterSprite.X = x;
            monsterSprite.Y = y;

            //if (Rnd.Next(2) == 0)
            //{
            //    monsterSprite.X = 256;
            //    monsterSprite.Y = 1;
            //}
            //else
            //{
            //    monsterSprite.X = 1;
            //    monsterSprite.Y = 161;
            //}

            //monsterSprite.SelectRandomDirection();
            monsterSprite.Viewport = Viewport;
            Collision monsterCollision = Viewport.SpriteWillCollideWithBackground(monsterSprite, monsterSprite.X, monsterSprite.Y, -1);
            while (monsterCollision.Collides())
            {
                monsterSprite.X = Rnd.Next(0, ViewportWidth - 32);
                monsterSprite.Y = Rnd.Next(0, ViewportHeight - 32);
                monsterCollision = Viewport.SpriteWillCollideWithBackground(monsterSprite, monsterSprite.X, monsterSprite.Y, 0);
            };

            Viewport.AddSprite("Monster" + Rnd.Next(), monsterSprite);

        }

        private void SwordHit(SwordSprite sword)
        {
           // sword.IsVisible = false;
        }

        private void SwordHitMonster(SwordSprite sword, ISprite monsterSprite)
        {
            MonsterKilled(monsterSprite);
            SwordHit(sword);
        }

        public void ShowSword(PlayerSprite player)
        {

            SwordSprite sword = (SwordSprite)Viewport.ActiveSprites["Sword"];

            if (!sword.IsVisible)
            {
                sword.IsVisible = true;
                sword.SetDirection(player.Direction);
                sword.Moving = false;
            }
        }

        private void PerformAreaTransition(SilverTileGameWorld gameWorld)
        {

            var monsterSprites = gameWorld.Viewport.ActiveSprites.Where(s => s.Value is MonsterSprite).ToList();
            monsterSprites.ForEach(m => gameWorld.Viewport.RemoveSprite(m.Key));
            _monstersHit.Clear();

        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}
